﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls.Primitives;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Input;

namespace Relay.UI.Controls.Docking.Primitives {
    /// <summary>
    /// Provides a control to resize docked elements in a DockManager
    /// </summary>
    public class DockManagerSplitter : Thumb {
        #region Fields
        private DockManager _host = null;
        private FrameworkElement _element = null;
        private SplitterAdorner _adorner = null;
        private Dock _dock = Dock.Left;
        private double _minElementDelta = 0.0;
        private double _maxElementDelta = 0.0;
        #endregion

        #region Constructor
        static DockManagerSplitter() {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DockManagerSplitter),
                new FrameworkPropertyMetadata(typeof(DockManagerSplitter)));

            EventManager.RegisterClassHandler(typeof(DockManagerSplitter), Thumb.DragStartedEvent,
                new DragStartedEventHandler(DragStartedHandler));
            EventManager.RegisterClassHandler(typeof(DockManagerSplitter), Thumb.DragDeltaEvent,
                            new DragDeltaEventHandler(DragDeltaHandler));
            EventManager.RegisterClassHandler(typeof(DockManagerSplitter), Thumb.DragCompletedEvent,
                new DragCompletedEventHandler(DragCompletedHandler));
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DockManagerSplitter"/> class.
        /// </summary>
        /// <param name="element">The element.</param>
        public DockManagerSplitter(FrameworkElement element, DockManager host) {
            _element = element;
            _host = host;

            _dock = DockManager.GetDock(element);
            _adorner = new SplitterAdorner(this);

            if (_dock == Dock.Left || _dock == Dock.Right)
                Cursor = Cursors.SizeWE;
            else
                Cursor = Cursors.SizeNS;
        }   
        #endregion

        #region Private Methods
        private void ThumbDragStarted(DragStartedEventArgs e) {
            double cellSize = DockManager.GetCellSize(_element);

            switch (_dock) {
                case Dock.Left:
                    _minElementDelta = DockManager.MinimumAreaSize - cellSize;
                    _maxElementDelta = _host.ContentRect.Width - DockManager.MinimumAreaSize;

                    break;
                case Dock.Right:
                    _maxElementDelta = cellSize - DockManager.MinimumAreaSize;
                    _minElementDelta = DockManager.MinimumAreaSize - _host.ContentRect.Width;

                    break;
                case Dock.Top:
                    _minElementDelta = DockManager.MinimumAreaSize - cellSize;
                    _maxElementDelta = _host.ContentRect.Height - DockManager.MinimumAreaSize;

                    break;
                case Dock.Bottom:
                    _maxElementDelta = cellSize - DockManager.MinimumAreaSize;
                    _minElementDelta = DockManager.MinimumAreaSize - _host.ContentRect.Height;

                    break;
            }

            _adorner.X = 0;
            _adorner.Y = 0;

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(_element);
            adornerLayer.Add(_adorner);
        }

        private void ThumbDragDelta(DragDeltaEventArgs e) {
            if (_dock == Dock.Right || _dock == Dock.Left) {
                _adorner.X = Math.Max(Math.Min(e.HorizontalChange, _maxElementDelta), _minElementDelta);
            } else {
                _adorner.Y = Math.Max(Math.Min(e.VerticalChange, _maxElementDelta), _minElementDelta);
            }
        }

        private void ThumbDragCompleted(DragCompletedEventArgs e) {
            double change = (_dock == Dock.Left || _dock == Dock.Right) ? _adorner.X : _adorner.Y;
            double newSize = DockManager.GetCellSize(_element);

            newSize += change * ((_dock == Dock.Right || _dock == Dock.Bottom) ? -1 : 1);
            DockManager.SetCellSize(_element, newSize);

            AdornerLayer adornerLayer = VisualTreeHelper.GetParent(_adorner) as AdornerLayer;
            adornerLayer.Remove(_adorner);
        }
        #endregion

        #region Overrides
        protected override Size MeasureOverride(Size constraint) {
            return new Size(DockManager.SplitterWidth, DockManager.SplitterWidth);
        } 
        #endregion

        #region Event Handlers
        private static void DragStartedHandler(object sender, DragStartedEventArgs e) {
            (sender as DockManagerSplitter).ThumbDragStarted(e);
        }

        private static void DragDeltaHandler(object sender, DragDeltaEventArgs e) {
            (sender as DockManagerSplitter).ThumbDragDelta(e);
        }

        private static void DragCompletedHandler(object sender, DragCompletedEventArgs e) {
            (sender as DockManagerSplitter).ThumbDragCompleted(e);
        }
        #endregion
    }
}
